<?php

namespace app\extensions\api;

use OSS\Core\OssException;
use OSS\Core\OssUtil;
use OSS\OssClient;
use support\Log;
use support\Redis;

class Oss{

    private $accessKeyId = 'LTAI5tAqJ8UNG6v3DhvHGh7J';
    private $accessKeySecret = "XlZuQa9705F1Ldi1V3F7lEEqyIFgkN";
    private $endpoint = "https://oss-cn-guangzhou.aliyuncs.com";
    const DOMAIN = 'https://ali-tapplus-oss-01.oss-cn-guangzhou.aliyuncs.com';
    public $timeout = 3600;
    public $connectTimeout = 20;
    public $bucket = "ali-tapplus-oss-01";//ali-tapplus-oss-01.oss-cn-guangzhou.aliyuncs.com
    private $ossClient;

    public function __construct()
    {
        $ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);//使用OSS域名新建OssClient  （使用自定义域名新建OssClient，使用STS新建OssClient，使用代理服务器新建OssClient）
        // 设置Socket层传输数据的超时时间，单位秒，默认5184000秒。
        $ossClient->setTimeout($this->timeout);
        // 设置建立连接的超时时间，单位秒，默认10秒。
        $ossClient->setConnectTimeout($this->connectTimeout);
        $this->ossClient = $ossClient;
    }

    public function upload($localPath,$ossPath,$is_del_local=false){
        $object = $ossPath;
        $putoptions = array(
            OssClient::OSS_HEADERS => array(
                'x-oss-object-acl' => 'public-read',
            ),
        );
        $object = trim($object,'/');
        $return = $this->ossClient->uploadFile($this->bucket, $object, $localPath,$putoptions);
        if($is_del_local && $return && isset($return['info'])){
            unlink($localPath);
        }
        Log::channel('oss')->info(json_encode($return));
        return $return['info'] ?: [];
    }

    public function uploadFileCallback($uploadFile,$ossPath,$is_del_local=false,$param=[]){
        $object = $ossPath;
        $putoptions = array(
            OssClient::OSS_HEADERS => array(
                'x-oss-object-acl' => 'public-read',
            ),
        );
        $ossClient = $this->ossClient;
        $object = trim($object,'/');
        $uploadId = $ossClient->initiateMultipartUpload($this->bucket, $object,$putoptions);

        $partSize = 10 * 1024 * 1024;
        $uploadFileSize = sprintf('%u',filesize($uploadFile));
        $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
        $responseUploadPart = array();
        $uploadPosition = 0;
        $isCheckMd5 = true;

        foreach ($pieces as $i => $piece) {
            $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
            $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
            $upOptions = array(
                $ossClient::OSS_FILE_UPLOAD => $uploadFile,
                $ossClient::OSS_PART_NUM => ($i + 1),
                $ossClient::OSS_SEEK_TO => $fromPos,
                $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
                $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
            );
            // MD5校验。
            if ($isCheckMd5) {
                $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
                $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
            }
            try {
                // 上传分片。
                $responseUploadPart[] = $ossClient->uploadPart($this->bucket, $object, $uploadId, $upOptions);
            } catch(OssException $e) {
                printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
                printf($e->getMessage() . "\n");
                return;
            }
            var_dump(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
        }

        $uploadParts = array();
        foreach ($responseUploadPart as $i => $eTag) {
            $uploadParts[] = array(
                'PartNumber' => ($i + 1),
                'ETag' => $eTag,
            );
        }

        $var = [];
        $i = 0;
        $body = '';
        foreach ($param as $key => $value){
            $i++;
            $var['x:var'.$i] = $value;
            $body .= '&'.$key .'=${x:var'.$i.'}';
        }
        $base_body = '{"mimeType":${mimeType},"size":${size}';
        $callback = [
            'callbackUrl' => 'https://test-admin.tapplus.com/api/oss_callback',
            'callbackHost' => 'test-admin.tapplus.com',
            'callbackBody' => $base_body.'&'.trim($body,'&'),
            'callbackBodyType' => 'application/x-www-form-urlencoded',
        ];

        $options = array(OssClient::OSS_CALLBACK => json_encode($callback),
            OssClient::OSS_CALLBACK_VAR => json_encode($var));
// 在执行该操作时，需要提供所有有效的$uploadParts。OSS收到提交的$uploadParts后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
        $data =$ossClient->completeMultipartUpload($this->bucket, $object, $uploadId, $uploadParts, $options);

        var_dump(__FUNCTION__ . ": completeMultipartUpload OK\n");

        return $data ?: [];
    }

    public function uploadContentsCallback(array $contents,$ossPath,$param,$callback,$position=0){

        $var = [];
        $i = 0;
        $body = '';
        foreach ($param as $key => $value){
            $i++;
            $var['x:var'.$i] = strval($value);
            $body .= '&'.$key .'=${x:var'.$i.'}';
        }
        $base_body = 'bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}';
        $callback = [
            'callbackUrl' => $callback,
            'callbackHost' => 'test-admin.tapplus.com',
            'callbackBody' => $base_body.'&'.trim($body,'&'),
            'callbackBodyType' => 'application/x-www-form-urlencoded',
        ];
        //dd($callback,$var);

        $ossClient = $this->ossClient;

        $options = array(OssClient::OSS_CALLBACK => json_encode($callback),
            OssClient::OSS_CALLBACK_VAR => json_encode($var),
            OssClient::OSS_HEADERS => array(
                'x-oss-object-acl' => 'public-read',
            ),
        );
        //dd($options);
        $result = [];
        foreach ($contents as $content){
            $position = $ossClient->appendObject($this->bucket, $ossPath, $content, $position,$options);
        }
        return $position;

    }
    public function getObject($key,$localfile=''){
        $localfile && $options = array(
            OssClient::OSS_FILE_DOWNLOAD => $localfile
        );
        $return['status'] = false;
        try{
            $content = $this->ossClient->getObject($this->bucket, $key,$options ?? []);
            $return['status'] = true;
            $return['content'] = $content;
        } catch(OssException $e) {
            $return['error'] =$e->getMessage();
        }
        return $return;
    }

    public function getObjectInfo($object,$is_all=true){
        try{
            if($is_all){
                $objectMeta = $this->ossClient->getObjectMeta($this->bucket, $object);
            }else{
                $objectMeta = $this->ossClient->getSimplifiedObjectMeta($this->bucket, $object);
            }
        }catch (OssException $e){
            $objectMeta = [];
        }


        return $objectMeta;
    }

    public function getPathList($dir = ''){
        $options = array(
            'prefix' => $dir,
        );
        /* @var $listObjectInfo \OSS\Model\ObjectListInfo */
        $listObjectInfo = $this->ossClient->listObjects($this->bucket,$options);

        $objectList = $listObjectInfo->getObjectList();
        $list = [];
        if (!empty($objectList)) {
            foreach ($objectList as $objectInfo) {
                //var_dump($objectInfo->getKey() . "\t" . $objectInfo->getSize() . "\t" . $objectInfo->getLastModified() . "\n");
                $list[] = $objectInfo->getKey();
            }
        }
        $pathList = $listObjectInfo->getPrefixList();
        if (!empty($pathList)) {
            foreach ($pathList as $prefixInfo) {
                $clist = $this->getPathList($prefixInfo->getPrefix());
                $list = array_merge($list,$clist);
            }
        }
        return $list;
    }

    public function getBuckets(){
        $options = [];
        return $this->ossClient->listBuckets();
    }

    public function deleteObject($object){
        Log::channel('oss')->warning('oss deleteObject:'.$object);
        return $this->ossClient->deleteObject($this->bucket, $object);
    }

    public function deleteList($path,$timeOutDate=30)
    {
        try{

            $list = $this->getPathList($path);
        } catch (OssException $e) {
            $list = [];
        }
        foreach ($list as $item){
            try{

                $info = $this->getObjectInfo($item);
            } catch (OssException $e) {

            }

            $last_modified = $info['last-modified'] ?? '';
            $object = $item;
            //dump($item.':'.strtotime($last_modified));
            if($last_modified && strtotime($last_modified) < time() - $timeOutDate *86400){
                $this->deleteObject($item);
                Redis::del(\app\queue\redis\download\DownToken::statusKey($object));
                Redis::del(\app\queue\redis\download\DownToken::positionKey($object));
            }


        }
    }
}